﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Net;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;

namespace SynchronizedPlayer
{
    class NetReceiver : IDisposable
    {
        const uint MAX_BUF_SIZE = 256;
        const int MAX_CONNECTIONS_ALLOWED = 10;

        Socket _listener;
        ConcurrentQueue<Command> _rcvQueue;
        IPEndPoint _localEndPoint;

        ManualResetEvent _receiveFirstDone = new ManualResetEvent(false);
        ManualResetEvent _receiveFullDone = new ManualResetEvent(false);

        public NetReceiver(int port, ConcurrentQueue<Command> rcvQueue)
        {
            _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
            _localEndPoint = new IPEndPoint(IPAddress.Any, port);
            _listener.Bind(_localEndPoint);
            _rcvQueue = rcvQueue;
            _listener.Listen(MAX_CONNECTIONS_ALLOWED);
            _listener.BeginAccept(acceptCallback, _listener);

        }

        void acceptCallback(IAsyncResult res)
        {
            try
            {
                Socket listener = (Socket)res.AsyncState;
                Socket handler = listener.EndAccept(res);


                byte[] buffer = new byte[1];

                handler.BeginReceive(buffer, 0, 1, SocketFlags.None, receiveFirstCallback, new Tuple<Socket, byte[]>(handler, buffer));
                _receiveFirstDone.WaitOne();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.StackTrace);
            }
        }
        void receiveFirstCallback(IAsyncResult res)
        {
            try
            {
                Socket listener = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item1;
                if (listener.EndReceive(res) == 1)
                {
                    _receiveFirstDone.Set();
                    byte[] buffer = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item2;
                    Socket handler = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item1;
                    byte size = buffer[0];
                    byte[] newbuffer = new byte[size];
                    handler.BeginReceive(newbuffer, 0, size, SocketFlags.None, receiveFullCallback, new Tuple<Socket, byte[]>(handler, newbuffer));
                    _receiveFullDone.WaitOne();
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.StackTrace);
            }
        }

        void receiveFullCallback(IAsyncResult res)
        {

            try
            {
                Socket listener = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item1;
                byte[] buffer = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item2;
                listener.EndReceive(res);
                _receiveFullDone.Set();
                _rcvQueue.Enqueue(Command.Parse(buffer));

                listener.Disconnect(true);

                _listener.Listen(MAX_CONNECTIONS_ALLOWED);
                _listener.BeginAccept(acceptCallback, _listener);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.StackTrace);
            }
        }

        public void Dispose()
        {
            _listener.Close();
        }
    }
}

